home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 2
/
Nebula Two.iso
/
SourceCode
/
GameKit
/
gamekit-1
/
HighScoreTable.m
< prev
next >
Wrap
Text File
|
1995-06-12
|
6KB
|
214 lines
#import <stdio.h> // strcpy
#import <stdlib.h> // malloc
#import <strings.h>
#import <objc/typedstream.h> // highscore tables
#import <daymisckit/daymisckit.h>
#import <gamekit/gamekit.h>
#import <appkit/appkit.h>
#import <remote/NXProxy.h>
@implementation HighScoreTable
- init // designated initializer sets up game variables
{ // to sensible values.
[super init];
tag = 0;
title = [[DAYString alloc] init];
emptySlot = [[HighScoreSlot alloc] init]; // ***** use proper class
maxHighScores = MAXSCORES;
return self;
}
- setEmptySlotClass:classObject
{
if (emptySlot) [emptySlot free];
emptySlot = [[classObject alloc] init];
return self;
}
- setStringValue:(const char *)aString
{
[title setStringValue:aString];
return self;
}
- (BOOL)samePlayer:slot1 :slot2
{ // if the login names are same, assume same user. You can override this
// to go by machine name or whatever.
if (![slot1 userName] || ![slot2 userName]) return NO;
if (strcmp([slot1 userName], [slot2 userName])) return NO;
return YES;
}
- (int)numEntriesByPlayer:aSlot // return # of high scores player has
{
int i, count = 0;
for (i=0; i<[self count]; i++)
if ([self samePlayer:[self objectAt:i] :aSlot]) count++;
return count;
}
- (int)lowestSlotByPlayer:aSlot // return lowest scoring slot by player
{
int i;
// look for appropriate slot from end of list to front
for (i=[self count]-1; i>=0; i--)
if ([self samePlayer:[self objectAt:i] :aSlot])
return i;
// return [self count] if didn't find a slot that matches criteria
return [self count];
}
- (const char *)stringValue { return [title stringValue]; }
- (int)tag { return tag; }
- setTag:(int)newTag { tag = newTag; return self; }
- (int)maxHighScores { return maxHighScores; }
- setMaxHighScores:(int)newMax
{
maxHighScores = newMax;
return self;
}
- (int)maxScoresPerPlayer { return maxScoresPerPlayer; }
- setMaxScoresPerPlayer:(int)newMax
{
maxScoresPerPlayer = newMax;
return self;
}
- (BOOL)addSlot:newSlot // keeps the table sorted as slots are added.
{
int i;
return [self addSlot:newSlot where:&i];
}
- (BOOL)addSlot:newSlot where:(int *)w // keeps table sorted as slots added.
{ // the key for the sort is from slots' -isAbove method...
int i; id xtraObj;
for (i=0; i<[self count]; i++) { // find where to add slot
if ([newSlot isAbove:[self objectAt:i]]) break;
} // insert it
[self insertObject:newSlot at:i]; // insert regardless
if (maxScoresPerPlayer) { // 0 == unlimited entries
if ([self numEntriesByPlayer:newSlot] > maxScoresPerPlayer) {
// have one more entry by this player than allowed, so
// we'll delete the lowest.
int xtraSlotNum = [self lowestSlotByPlayer:newSlot];
#ifdef NOISYDEBUG
fprintf(stderr,
"HighScoreTable: removing extra entry by player %s.\n",
[newSlot userName]);
#endif
// delete the actual slot and free it.
xtraObj = [self removeObject:[self objectAt:xtraSlotNum]];
if ([xtraObj isProxy]) [xtraObj freeProxy];
else [xtraObj free];
// if this was the slot we just added, then return
// that we didn't add it after all...
if (i == xtraSlotNum) {
*w = [self count];
return NO;
}
}
}
// prune the table so it doesn't grow too big. max # is set by init.
// done by deleting slots from the end to the front until size is OK.
while ([self count] > maxHighScores) {
xtraObj = [self removeLastObject];
if ([xtraObj isProxy]) [xtraObj freeProxy];
else [xtraObj free];
}
*w = i; // return by reference where we added it.
if (i >= maxHighScores) return NO;
return YES;
}
- objectAt:(unsigned)index
{
if (index >= [self count]) return emptySlot;
return [super objectAt:index];
}
- free
{
[emptySlot free];
return [super free];
}
- copy
{ // build a new table with new slots (i.e. don't just copy id pointers,
// actually make new objects)
int i; id aCopy = [[[self class] alloc] init];
[aCopy setEmptySlotClass:[emptySlot class]];
[aCopy setMaxHighScores:maxHighScores];
for (i=0; i<[self count]; i++) {
[aCopy addSlot:[[self objectAt:i] copy]];
}
return aCopy;
}
- read:(NXTypedStream *)stream
{ // don't save emptySlot since it is easy enough to create
[super read:stream];
NXReadTypes(stream, "iii", &maxHighScores, &maxScoresPerPlayer, &tag);
emptySlot = NXReadObject(stream);
title = NXReadObject(stream);
return self;
}
- write:(NXTypedStream *)stream
{
[super write:stream];
NXWriteTypes(stream, "iii", &maxHighScores, &maxScoresPerPlayer, &tag);
NXWriteObject(stream, emptySlot); // saved to preserve class type
NXWriteObject(stream, title);
return self;
}
// NXTransport protocol implementation: List must contain objects that
// also use this protocol; otherwise it won't xfer by copy properly!
- encodeUsing:(id <NXEncoding>)portal
{
int i, n = [self count];
[portal encodeData:&n ofType:"i"];
[portal encodeData:&maxHighScores ofType:"i"];
[portal encodeData:&maxScoresPerPlayer ofType:"i"];
[portal encodeData:&tag ofType:"i"];
for (i=0; i<n; i++) {
[portal encodeObjectBycopy:[self objectAt:i]];
}
[portal encodeObjectBycopy:emptySlot];
[portal encodeObjectBycopy:title];
return self;
}
- decodeUsing:(id <NXDecoding>)portal
{
int i, n;
[portal decodeData:&n ofType:"i"];
[portal decodeData:&maxHighScores ofType:"i"];
[portal decodeData:&maxScoresPerPlayer ofType:"i"];
[portal decodeData:&tag ofType:"i"];
[self freeObjects]; // make sure that we're empty
for (i=0; i<n; i++) {
[self addObject:[portal decodeObject]];
}
emptySlot = [portal decodeObject];
title = [portal decodeObject];
return self;
}
- encodeRemotelyFor:(NXConnection *)connection
freeAfterEncoding:(BOOL *)flagp isBycopy:(BOOL)isByCopy
{
if (isByCopy) return self; //encode object (copy it)
// super will encode the proxy otherwise
return [super encodeRemotelyFor:connection
freeAfterEncoding:flagp isBycopy:isByCopy];
}
@end